extends Window

#region Contant
## 没有预览任何文件时的索引
const PREVIEW_FILE_HEADER_INDEX_NONE: int = -1
#endregion Contant

#region Variables
## pak文件对象
var pakFile: PakFile = null
## 加载文件对话框
var _loadFileDialog: FileDialog = null

## 预览复选框
@onready var check_box_preview: CheckBox = $MarginContainer/VBoxContainer/HBoxContainerToolStrip/CheckBoxPreview
## 十六进制空格复选框
@onready var check_box_hex_spacing: CheckBox = $MarginContainer/VBoxContainer/HBoxContainerToolStrip/CheckBoxHexSpacing
## 是否修改pak文件标签
@onready var label_is_changed: Label = $MarginContainer/VBoxContainer/HBoxContainerToolStrip/LabelIsChanged
## pak文件路径标签
@onready var label_path: Label = $MarginContainer/VBoxContainer/HBoxContainerToolStrip/LabelPath
## 文件夹下拉列表框
@onready var option_button_folder: OptionButton = $MarginContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/OptionButtonFolder
## 文件类型下拉列表框
@onready var option_button_file_type: OptionButton = $MarginContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/OptionButtonFileType
## 过滤文本框
@onready var line_edit_filter: LineEdit = $MarginContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/LineEditFilter
## pak文件头列表框
@onready var item_list_pak_file_header: ItemList = $MarginContainer/VBoxContainer/HSplitContainer/VBoxContainer/ItemListPakFileHeader
## 文件内容文本
@onready var text_edit_pak_file_content: TextEdit = $MarginContainer/VBoxContainer/HSplitContainer/VSplitContainer/PanelContainer/TextEditPakFileContent
## 文件内容纹理矩形
@onready var texture_rect_pak_file_content: TextureRect = $MarginContainer/VBoxContainer/HSplitContainer/VSplitContainer/PanelContainer/TextureRectPakFileContent
## 文件内容视频播放器
@onready var video_stream_player_pak_file_content: VideoStreamPlayer = $MarginContainer/VBoxContainer/HSplitContainer/VSplitContainer/PanelContainer/VideoStreamPlayerPakFileContent
## 文件内容音频播放器
@onready var audio_stream_player_pak_file_content: AudioStreamPlayer = $MarginContainer/VBoxContainer/HSplitContainer/VSplitContainer/PanelContainer/AudioStreamPlayerPakFileContent
## 文件内容十六进制文本
@onready var text_edit_hex_pak_file_content: TextEdit = $MarginContainer/VBoxContainer/HSplitContainer/VSplitContainer/TextEditHexPakFileContent

## 十六进制文本框中，每行显示多少个字符
@export_range(10, 999, 10) var lineLengthOfHexContent: int = 20
#endregion Variables

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	InitLoadFileDialog()

## 初始化加载文件对话框
func InitLoadFileDialog() -> void:
	_loadFileDialog = FileDialog.new()
	_loadFileDialog.access = FileDialog.Access.ACCESS_FILESYSTEM
	_loadFileDialog.file_mode = FileDialog.FileMode.FILE_MODE_OPEN_FILE
	_loadFileDialog.add_filter("*.pak", "pak文件")
	_loadFileDialog.title = "打开pak文件"
	_loadFileDialog.cancel_button_text = "取消"
	_loadFileDialog.ok_button_text = "打开"
	_loadFileDialog.size = Vector2i(480, 320)
	_loadFileDialog.always_on_top = true
	_loadFileDialog.exclusive = true
	add_child(_loadFileDialog)
	_loadFileDialog.move_to_center()
	_loadFileDialog.file_selected.connect(LoadPakFile)

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	pass

## 新建pak文件
func _on_button_new_pressed() -> void:
	if pakFile and pakFile.GetIsChanged():
		print("已经打开未保存的pak文件。")
		return
	pakFile = PakFile.new()
	ShowPakFile()

## 加载pak文件
func _on_button_load_pressed() -> void:
	if pakFile and pakFile.GetIsChanged():
		print("已经打开未保存的pak文件。")
		return
	_loadFileDialog.show()

## 加载pak文件
## 参数：
## filename-pak文件名
## 返回：无
func LoadPakFile(filename: String) -> void:
	print("open file ", filename)
	var loadResult: ActionResultWithData = PakFile.Load(filename)
	if loadResult.Success():
		pakFile = loadResult.Data as PakFile
	else:
		pakFile = null
	ShowPakFile()

## 显示空白文件内容
func ShowEmptyContent() -> void:
	text_edit_pak_file_content.text = ""
	text_edit_pak_file_content.hide()
	texture_rect_pak_file_content.texture = null
	texture_rect_pak_file_content.hide()
	video_stream_player_pak_file_content.stop()
	video_stream_player_pak_file_content.stream = null
	video_stream_player_pak_file_content.hide()
	audio_stream_player_pak_file_content.stop()
	audio_stream_player_pak_file_content.stream = null
	text_edit_hex_pak_file_content.text = ""
	
## 显示文件内容
## 参数：
## idx-文件头所在的索引
func ShowContent(idx: int) -> void:
	if (not check_box_preview.button_pressed or idx == PREVIEW_FILE_HEADER_INDEX_NONE or 
		not pakFile or idx > pakFile.GetHeadersCount()-1):
		return
	#显示空白文件内容
	ShowEmptyContent()
	#预览文件内容
	var buffer: PackedByteArray = pakFile.GetContent(idx)
	if buffer == null or buffer.is_empty():
		return
	var header: PakFileHeader = pakFile.Headers[idx]
	PreviewContent(header.FileName, buffer)
	
## 预览十六进制文件内容
## 参数：
## buffer-文件内容字节数组
func PreviewHexContent(buffer: PackedByteArray) -> void:
	var formatter: String = "%02x"
	var newLine: String = "\n"
	var spacing: String = " "
	var needSpacing: bool = check_box_hex_spacing.button_pressed
	var stringArray: PackedStringArray = PackedStringArray()
	var idx: int = 0
	for b in buffer:
		stringArray.append(formatter % b)
		idx = idx + 1
		if idx % lineLengthOfHexContent == 0:
			stringArray.append(newLine)
		elif needSpacing:
			stringArray.append(spacing)
	text_edit_hex_pak_file_content.text = "".join(stringArray)
	
## 预览图片内容
## 参数：
## extension-扩展名
## buffer-内容
func PreviewImageContent(extension: String, buffer: PackedByteArray) -> void:
	var texture: Texture2D
	if extension == "gif":
		texture = GifManager.animated_texture_from_buffer(buffer)
	else:
		var image: Image = Image.new()
		var error: Error = OK
		if extension == "bmp":
			error = image.load_bmp_from_buffer(buffer)
		elif extension == "jpg" or extension == "jpeg":
			error = image.load_jpg_from_buffer(buffer)
		elif extension == "ktx":
			error = image.load_ktx_from_buffer(buffer)
		elif extension == "png":
			error = image.load_png_from_buffer(buffer)
		elif extension == "svg":
			error = image.load_svg_from_buffer(buffer)
		elif extension == "tga":
			error = image.load_tga_from_buffer(buffer)
		elif extension == "webp":
			error = image.load_webp_from_buffer(buffer)
		if error != OK:
			printerr("加载图片错误：", error)
			return
		var imageTexture: ImageTexture = ImageTexture.create_from_image(image)
		texture = imageTexture
	texture_rect_pak_file_content.texture = texture
	texture_rect_pak_file_content.show()

## 预览视频内容
## 参数：
## filename-文件名
## buffer-内容
func PreviewVideoContent(filename: String, buffer: PackedByteArray) -> void:
	var extension: String = filename.get_extension()
	var tempFile: FileAccess = FileAccess.create_temp(FileAccess.WRITE, "pak_video", extension, true)
	if not tempFile:
		print("创建临时文件失败：", FileAccess.get_open_error())
		return
	tempFile.store_buffer(buffer)
	var tempFilePath: String = tempFile.get_path_absolute()
	tempFile.close()
	var video: VideoStreamTheora = VideoStreamTheora.new()
	video.file  = tempFilePath
	video_stream_player_pak_file_content.stream = video
	video_stream_player_pak_file_content.play()
	video_stream_player_pak_file_content.show()

## 预览音频内容
## 参数：
## extension-扩展名
## buffer-内容
func PreviewAudioContent(extension: String, buffer: PackedByteArray) -> void:
	var audio: AudioStream
	if extension == "ogg":
		audio = AudioStreamOggVorbis.load_from_buffer(buffer)
	elif extension == "wav":
		var wav: AudioStreamWAV = AudioStreamWAV.new()
		wav.data = buffer
		audio = wav
	elif extension == "mp3":
		var mp3: AudioStreamMP3 = AudioStreamMP3.new()
		mp3.data = buffer
		audio = mp3
	audio_stream_player_pak_file_content.stream = audio
	audio_stream_player_pak_file_content.play()
		
## 预览文本内容
## 参数：
## buffer-内容
func PreviewTextContent(buffer: PackedByteArray) -> void:
	var content: String = ""
	var encoding: EncodingHelper.Encoding = EncodingHelper.GetEncoding(buffer)
	if encoding == EncodingHelper.Encoding.UTF32:
		content = buffer.get_string_from_utf32()
	elif encoding == EncodingHelper.Encoding.UTF16:
		content = buffer.get_string_from_utf16()
	else:
		content = buffer.get_string_from_utf8()
	text_edit_pak_file_content.text = content
	text_edit_pak_file_content.show()

## 预览文件内容
## 参数：
## filename-文件名
## buffer-文件内容字节数组
func PreviewContent(filename: String, buffer: PackedByteArray) -> void:
	#预览十六进制文件内容
	PreviewHexContent(buffer)
	#根据文件格式分别预览
	var extension: String = filename.get_extension().to_lower()
	var imageExtensions: Array[String] = [ "bmp", "jpg", "jpeg", "ktx", "png", 
		"svg", "tga", "webp", "gif" ]
	var videoExtensions: Array[String] = [ "ogv" ]
	var audioExtensions: Array[String] = [ "mp3", "ogg", "wav" ]
	var textExtensions: Array[String] = [ "txt", "xml", "reanim", "trail", "sig", "jsfl" ]
	if extension in imageExtensions:
		PreviewImageContent(extension, buffer)
	elif extension in videoExtensions or (extension == "ogg" and OggHelper.IsOggBufferContainsVideo(buffer)):
		PreviewVideoContent(filename, buffer)
	elif extension in audioExtensions:
		PreviewAudioContent(extension, buffer)
	elif extension in textExtensions:
		PreviewTextContent(buffer)

## 显示pak文件
func ShowPakFile() -> void:
	ShowEmptyContent()
	option_button_folder.clear()
	option_button_file_type.clear()
	line_edit_filter.text = ""
	item_list_pak_file_header.clear()
	if pakFile:
		label_is_changed.text = "*" if pakFile.GetIsChanged() else ""
		label_path.text = pakFile.GetPath()
		label_path.tooltip_text = pakFile.GetPath()
		RefreshFilterControls()
		FilterFileHeader()
	else:
		label_is_changed.text = ""
		label_path.text = ""

## 刷新过滤控件：文件夹、文件类型、过滤通配符
func RefreshFilterControls() -> void:
	if pakFile.GetHeadersCount() > 0:
		var folders: Dictionary[String, String] = { "": "" }	#目录字典，键和值都为目录名
		var fileTypes: Dictionary[String, String] = { "*.*": "*.*" }	#文件类型字典，键和值都为文件类型
		var folder: String
		var fileType: String
		for header: PakFileHeader in pakFile.Headers:
			folder = header.FileName.get_base_dir()
			if folder:
				folders[folder] = folder
			fileType = header.FileName.get_extension()
			if fileType:
				fileType = "*.{0}".format([ fileType ])
				fileTypes[fileType] = fileType
		var foldersArray: Array[String] = folders.keys()
		foldersArray.sort()
		for folderName: String in foldersArray:
			option_button_folder.add_item(folderName)
		var fileTypesArray: Array[String] = fileTypes.keys()
		fileTypesArray.sort()
		for fileTypeName: String in fileTypesArray:
			option_button_file_type.add_item(fileTypeName)
	
## 筛选文件头
func FilterFileHeader() -> void:
	item_list_pak_file_header.clear()
	if pakFile and pakFile.GetHeadersLength() > 0:
		#路径过滤字符串
		var pathFilter: String = GetPathFilter()
		#过滤字符串
		var filter: String = GetFilter()
		#文件头所在的索引
		var index: int = 0
		for header: PakFileHeader in pakFile.Headers:
			if header.FileName.match(pathFilter) and header.FileName.matchn(filter):
				AddFileHeaderToItemList(header, index)
			index = index + 1

## 获取过滤文件路径的字符串
## 返回：过滤文件路径的字符串
func GetPathFilter() -> String:
	var folder: String = ""
	var fileType: String = "*.*"
	var folderIndex: int = option_button_folder.selected
	if folderIndex != -1:
		folder = option_button_folder.get_item_text(folderIndex)
	var fileTypeIndex: int = option_button_file_type.selected
	if fileTypeIndex != -1:
		fileType = option_button_file_type.get_item_text(fileTypeIndex)
	if folder == "":
		return fileType
	else:
		return "{0}\\{1}".format([ folder, fileType ])

## 获取过滤通配符字符串
## 返回过滤通配符字符串
func GetFilter() -> String:
	var filter: String = line_edit_filter.text
	if filter == "":
		filter = "*"
	else:
		if not filter.begins_with("*") and not filter.begins_with("?"):
			filter = "*" + filter
		if not filter.ends_with("*") and not filter.ends_with("?"):
			filter = filter + "*"
	return filter

## 将文件头添加到列表框中
## 参数：
## header-文件头
## index-文件头所在的索引
## 返回：文件头在列表中的索引
func AddFileHeaderToItemList(header: PakFileHeader, index: int) -> int:
	var idx: int = item_list_pak_file_header.add_item(header.FileName)
	var time: String = Time.get_datetime_string_from_datetime_dict(header.FileTimeDict, true)
	var tooltip = "名称：{0}\n大小：{1}\n时间：{2}\n索引：{3}".format([ header.FileName, header.FileSize, time, index ])
	item_list_pak_file_header.set_item_tooltip(idx, tooltip)
	item_list_pak_file_header.set_item_metadata(idx, index)
	return idx

func _on_button_save_pressed() -> void:
	pass # Replace with function body.


func _on_button_save_as_pressed() -> void:
	pass # Replace with function body.

## 文件头选择事件。如果选择了文件头，根据需要预览最后一个选定的文件头。
## 参数：
## index-更改选择时点击的项索引
## selected-是否选定了点击的项
func _on_item_list_pak_file_header_multi_selected(index: int, selected: bool) -> void:
	# 获取当前待显示的文件头索引
	var currentIndex: int = PREVIEW_FILE_HEADER_INDEX_NONE
	if item_list_pak_file_header.is_anything_selected():
		var lastIndex: int = item_list_pak_file_header.get_selected_items()[-1]
		currentIndex = item_list_pak_file_header.get_item_metadata(lastIndex) as int
	# 视需要预览文件
	if check_box_preview.button_pressed and currentIndex != PREVIEW_FILE_HEADER_INDEX_NONE:
		# 显示选中的文件
		ShowContent(currentIndex)
	else:
		ShowEmptyContent()

## 改变文件路径时，筛选文件头
func _on_option_button_folder_item_selected(index: int) -> void:
	var folder: String = option_button_folder.get_item_text(index)
	option_button_folder.tooltip_text = "文件夹\n{0}".format([ folder ])
	FilterFileHeader()

## 改变文件类型时，筛选文件头
func _on_option_button_file_type_item_selected(index: int) -> void:
	var fileType: String = option_button_file_type.get_item_text(index)
	option_button_file_type.tooltip_text = "文件类型\n{0}".format([ fileType ])
	FilterFileHeader()

## 改变文件过滤通配符时，筛选文件头
func _on_line_edit_filter_text_changed(new_text: String) -> void:
	FilterFileHeader()

func _on_button_unpack_file_pressed() -> void:
	pass # Replace with function body.


func _on_button_unpack_all_pressed() -> void:
	pass # Replace with function body.


func _on_button_append_pressed() -> void:
	pass # Replace with function body.


func _on_button_insert_pressed() -> void:
	pass # Replace with function body.


func _on_button_update_pressed() -> void:
	pass # Replace with function body.


func _on_button_delete_pressed() -> void:
	pass # Replace with function body.


func _on_button_delete_all_pressed() -> void:
	print("os temp dir:", OS.get_temp_dir())
	var f = FileAccess.create_temp(FileAccess.WRITE, "a", ".ogv", false)
	print("temp file path:", f.get_path())
	print("temp file absolute path:", f.get_path_absolute())
	f.close()
	# todo：调试视频播放，设置大小。
	var video: VideoStreamTheora = VideoStreamTheora.new()
	video.file  = "d:/拉霍亚的日出.ogg"
	video_stream_player_pak_file_content.stream = video
	video_stream_player_pak_file_content.play()
	video_stream_player_pak_file_content.show()
	
	pass # Replace with function body.

## 切换预览的勾选状态时
func _on_check_box_preview_toggled(toggled_on: bool) -> void:
	_on_item_list_pak_file_header_multi_selected(PREVIEW_FILE_HEADER_INDEX_NONE, false)

## 切换十六进制空格的勾选状态时
func _on_check_box_hex_spacing_toggled(toggled_on: bool) -> void:
	_on_item_list_pak_file_header_multi_selected(PREVIEW_FILE_HEADER_INDEX_NONE, false)


func _on_files_dropped(files: PackedStringArray) -> void:
	pass # Replace with function body.


func _on_close_requested() -> void:
	pass # Replace with function body.


func _on_go_back_requested() -> void:
	pass # Replace with function body.


func ShowLoading(text: String) -> void:
	return
	

func HideLoading() -> void:
	return
